package com.bracketbird.client.model.tournament;

import com.bracketbird.client.model.*;
import com.bracketbird.client.model.keys.*;
import com.bracketbird.clientcore.model.*;

import java.util.*;

/**
 *
 */
public class Match extends Model<MatchId> {
    private static final long serialVersionUID = -8624209794497350221L;

    private transient List<TournamentListener<MatchEvent>> matchListener = new ArrayList<TournamentListener<MatchEvent>>();


    private ClubId clubId;

    private TournamentLevel level;

    //used in group-play
    private String groupName;

    //what round does this match belong to
    private Long round;

    //the order of the match in a subtournament
    private Integer order;

    //used in knockout - to reference between mathces (who meets who).
    private String name;

    private PlayingTeam teamHome;

    private PlayingTeam teamOut;


    private Date createdDate;

    private Date lastChangeDate;

    private Result result;

    private String field;


    public Match() {

    }

    @Override
    public MatchId createLocalId() {
        return new MatchId();
    }


    public ClubId getClubId() {
        return clubId;
    }

    public void setClubId(ClubId clubId) {
        this.clubId = clubId;
    }

    public PlayingTeam getTeamHome() {
        return teamHome;
    }

    public void setTeamHome(PlayingTeam teamHome) {
        this.teamHome = teamHome;
    }

    public PlayingTeam getTeamOut() {
        return teamOut;
    }

    public void setTeamOut(PlayingTeam teamOut) {
        this.teamOut = teamOut;

    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Long getRound() {
        return round;
    }

    public void setRound(Long round) {
        this.round = round;
    }

    public Integer getOrder() {
        return order;
    }

    public void setOrder(Integer order) {
        this.order = order;
    }


    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public Date getLastChangeDate() {
        return lastChangeDate;
    }

    public void setLastChangeDate(Date lastChangeDate) {
        this.lastChangeDate = lastChangeDate;
    }

    public void addMatchChangedListener(TournamentListener<MatchEvent> l) {
        this.matchListener.add(l);
    }

    public void setResult(Result r) {
        result = r;
    }

    private void fireMatchChangedEvent(boolean fromClient) {
        MatchEvent event = new MatchEvent(fromClient, this);
        for (TournamentListener<MatchEvent> l : matchListener) {
            l.onChange(event);
        }
    }


    public String getField() {
        return field;
    }

    public void setField(String f) {
        this.field = f;
    }


    public boolean hasResult() {
        return result != null;
    }

    public PlayingTeam getWinningTeam(){
        if(!isFinish()){
            return null;
        }
        if(isWalkover()){
            return getTeamHome() instanceof WalkOverTeam ? getTeamOut() : getTeamHome();
        }
        return homeIsWinning() ? getTeamHome() : getTeamOut();
    }

    public PlayingTeam getLosingTeam(){
        if(!isFinish()){
            return null;
        }
        if(isWalkover()){
            return getTeamHome() instanceof WalkOverTeam ? getTeamHome() : getTeamOut();
        }
        return homeIsWinning() ? getTeamOut() : getTeamHome();
    }



    public boolean homeIsWinning() {
        return hasResult() && result.homeIsWinning();
    }

    public boolean outIsWinning() {
        return hasResult() && result.outIsWinning();
    }

    public boolean isDraw() {
        return hasResult() && result.isDraw();
    }

    public String resultAsString() {
        return !hasResult() ? "" : result.asString();
    }


    public Result getResult() {
        return result;
    }

    public boolean isFinish() {
        return result != null || isWalkover();
    }

    public boolean isHome(PlayingTeamId id) {
        return teamHome.equals(id);
    }

    public TournamentLevel getLevel() {
        return level;
    }

    public void setLevel(TournamentLevel level) {
        this.level = level;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public boolean isWalkover() {
        return getTeamHome() instanceof WalkOverTeam || getTeamOut() instanceof WalkOverTeam;
    }

    public MatchVO createVO() {
        MatchVO vo = new MatchVO();
        vo.setField(getField());
        vo.setRound(getRound());
        vo.setGroupName(getGroupName());
        vo.setName(getName());
        vo.setLastChangeDate(getLastChangeDate());
        vo.setOrder(getOrder());
        vo.setResult(getResult());
        vo.setTeamOut(getTeamOut().getId());
        vo.setTeamHome(getTeamHome().getId());
        return vo;
    }


    void update(MatchVO vo, boolean fromClient) {
        setField(vo.getField());
        setRound(vo.getRound());
        setGroupName(vo.getGroupName());
        setName(vo.getName());
        setLastChangeDate(vo.getLastChangeDate());
        setOrder(vo.getOrder());
        setResult(vo.getResult());
        setTeamOut(level.getTeam(vo.getTeamOut()));
        setTeamHome(level.getTeam(vo.getTeamHome()));
        fireMatchChangedEvent(fromClient);
        if(isFinish()){
            level.updateMatchInNextRound(this);
        }
    }

    public void updateHomeTeam(PlayingTeam home, boolean fromClient){
        this.teamHome = home;
        fireMatchChangedEvent(fromClient);
    }

    public void updateOutTeam(PlayingTeam out, boolean fromClient){
        this.teamOut = out;
        fireMatchChangedEvent(fromClient);
    }

    public boolean isSame(MatchVO vo){
        if(round.longValue() == vo.getRound()){
            if(groupName == null || groupName.equals(vo.getGroupName()) ){
                return order.intValue() == vo.getOrder();
            }
        }
        return false;
    }


    @Override
    public String toString() {
        return "Match{" + teamHome + " - " + teamOut + '}';
    }

}